#include "sysmonitor/network_tools.hpp"
#include "sysmonitor/utils.hpp"
#include <fstream>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <ifaddrs.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <map>


namespace sysmonitor {
namespace network {

using namespace utils;
using namespace utils::string;

NetworkMonitor::NetworkMonitor() : previousTime_(std::chrono::system_clock::now()) {}

std::vector<NetworkInterface> NetworkMonitor::getNetworkInterfaces() {
    std::vector<NetworkInterface> interfaces;
    std::map<std::string, NetworkInterface> ifaceMap;

    ifaddrs* ifAddrStruct = nullptr;
    if (getifaddrs(&ifAddrStruct) == -1) {
        std::cerr << "Failed to get network interfaces: " << strerror(errno) << std::endl;
        return interfaces;
    }
  
    for (ifaddrs* ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr || (ifa->ifa_flags & IFF_LOOPBACK)) continue;

        std::string name = ifa->ifa_name;
        ifaceMap[name].name = name;
        ifaceMap[name].isUp = (ifa->ifa_flags & IFF_UP);
        
        if (ifa->ifa_addr->sa_family == AF_INET) { // IPv4
            char addrBuf[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(ifa->ifa_addr)->sin_addr, addrBuf, sizeof(addrBuf));
            ifaceMap[name].ipAddress = addrBuf;
        } else if (ifa->ifa_addr->sa_family == AF_PACKET && ifaceMap[name].macAddress.empty()) { // MAC Address
            struct sockaddr_ll* s = reinterpret_cast<struct sockaddr_ll*>(ifa->ifa_addr);
            std::stringstream ss;
            ss << std::hex << std::setfill('0');
            for(int i = 0; i < s->sll_halen; i++) {
                ss << (i == 0 ? "" : ":") << std::setw(2) << static_cast<int>(s->sll_addr[i]);
            }
            ifaceMap[name].macAddress = ss.str();
        }
    }
    freeifaddrs(ifAddrStruct);

    // 获取流量信息
    std::ifstream netDev("/proc/net/dev");
    if (netDev.is_open()) {
        std::string line;
        std::getline(netDev, line); // Skip header
        std::getline(netDev, line); // Skip header
        while (std::getline(netDev, line)) {
            std::istringstream ss(line);
            std::string ifaceName;
            ss >> ifaceName;
            if (ifaceName.back() == ':') {
                ifaceName.pop_back();
            }

            auto it = ifaceMap.find(ifaceName);
            if (it != ifaceMap.end()) {
                // Col 0: Recv Bytes, Col 8: Sent Bytes
                uint64_t rx, p1, p2, p3, p4, p5, p6, p7, tx;
                ss >> rx >> p1 >> p2 >> p3 >> p4 >> p5 >> p6 >> p7 >> tx;
                it->second.bytesReceived = rx;
                it->second.bytesSent = tx;
            }
        }
        netDev.close();
    }

    for(const auto& pair : ifaceMap) {
        interfaces.push_back(pair.second);
    }
    return interfaces;
}

std::vector<NetworkTraffic> NetworkMonitor::getCurrentTraffic() {
    std::vector<NetworkTraffic> traffic;
    auto interfaces = getNetworkInterfaces();
    auto timestamp = std::chrono::system_clock::now();

    for (const auto& iface : interfaces) {
        if (!iface.isUp) continue;
        NetworkTraffic t;
        t.interface = iface.name;
        t.bytesReceived = iface.bytesReceived;
        t.bytesSent = iface.bytesSent;
        t.timestamp = timestamp;
        traffic.push_back(t);
    }
    return traffic;
}

std::vector<NetworkTraffic> NetworkMonitor::calculateTrafficRates() {
    auto currentTraffic = getCurrentTraffic();
    auto currentTime = std::chrono::system_clock::now();
    std::vector<NetworkTraffic> result;

    auto timeDiff = std::chrono::duration<double>(currentTime - previousTime_).count();
    if (previousTraffic_.empty() || timeDiff <= 0) {
        previousTraffic_ = std::move(currentTraffic);
        previousTime_ = currentTime;
        return currentTraffic; // 返回当前流量，但速率为0
    }

    for (const auto& current : currentTraffic) {
        auto it = std::find_if(previousTraffic_.begin(), previousTraffic_.end(),
            [&](const NetworkTraffic& prev) { return prev.interface == current.interface; });

        if (it != previousTraffic_.end()) {
            NetworkTraffic rate = current;
            uint64_t rxDiff = current.bytesReceived > it->bytesReceived ? current.bytesReceived - it->bytesReceived : 0;
            uint64_t txDiff = current.bytesSent > it->bytesSent ? current.bytesSent - it->bytesSent : 0;
            rate.receiveRate = static_cast<double>(rxDiff) / timeDiff;
            rate.sendRate = static_cast<double>(txDiff) / timeDiff;
            result.push_back(rate);
        }
    }

    previousTraffic_ = std::move(currentTraffic);
    previousTime_ = currentTime;
    return result;
}

} // namespace network
} // namespace sysmonitor
